//
//  BroadcastTest.swift
//  SwiftTools
//
//  Created by Samuel Richard Magny on 15-10-02.
//  Copyright © 2015 Samuel Richard Magny. All rights reserved.
//

import XCTest
import SwiftTools

class BroadcastTest: XCTestCase {

    let broadcastCenter = BroadcastCenter.defaultCenter()
    let broadCastIdentifier:String = "id"
    let broadCastIdentifier2:String = "id2"
    
    override func setUp() {
        super.setUp()
        
        AssertThatReceiverCountIs(0, identifier: broadCastIdentifier)
        AssertThatReceiverCountIs(0, identifier: broadCastIdentifier2)
    }
    
    override func tearDown() {
        AssertThatReceiverCountIs(0, identifier: broadCastIdentifier)
        AssertThatReceiverCountIs(0, identifier: broadCastIdentifier2)
        
        super.tearDown()
    }

    func testBasicNotification() {
        
        broadcastCenter.subscribe(self, selector: "getBroadcast:", identifier: broadCastIdentifier)

        let notification = BroadcastNotification(sender:self, identifier:broadCastIdentifier)
        broadcastCenter.post(notification)
        
        broadcastCenter.unSubscribe(self, identifier: broadCastIdentifier)
    }
    
    func testAddingAndRemovingObserverWithSameIdentifier() {
        
        let receiver1 = NotificationReceiver(identifier: broadCastIdentifier, broadcastCenter: broadcastCenter)
        AssertThatReceiverCountIs(1)
        AssertThatReceiverIsInList(receiver1)
        
        let receiver2 = NotificationReceiver(identifier: broadCastIdentifier, broadcastCenter: broadcastCenter)
        AssertThatReceiverCountIs(2)
        AssertThatReceiverIsInList(receiver2)
        
        let receiver3 = NotificationReceiver(identifier: broadCastIdentifier, broadcastCenter: broadcastCenter)
        AssertThatReceiverCountIs(3)
        AssertThatReceiverIsInList(receiver3)
        
        receiver2.unSubscribe()
        AssertThatReceiverCountIs(2)
        AssertThatReceiverIsNotInList(receiver2)
        AssertThatReceiverIsInList(receiver1)
        AssertThatReceiverIsInList(receiver3)

        receiver2.subscribe()
        AssertThatReceiverCountIs(3)
        AssertThatReceiverIsInList(receiver1)
        AssertThatReceiverIsInList(receiver2)
        AssertThatReceiverIsInList(receiver3)
        
        receiver1.unSubscribe()
        AssertThatReceiverCountIs(2)
        AssertThatReceiverIsNotInList(receiver1)
        AssertThatReceiverIsInList(receiver2)
        AssertThatReceiverIsInList(receiver3)
        
        receiver3.unSubscribe()
        AssertThatReceiverCountIs(1)
        AssertThatReceiverIsInList(receiver2)
        AssertThatReceiverIsNotInList(receiver3)
        
        receiver2.unSubscribe()
        AssertThatReceiverCountIs(0)
    }
    
    func testAddingAndRemovingObserverWithDifferentIdentifiers() {
        let receiverA1 = NotificationReceiver(identifier: broadCastIdentifier, broadcastCenter: broadcastCenter)
        AssertThatReceiverCountIs(1, identifier:broadCastIdentifier)
        
        let receiverB1 = NotificationReceiver(identifier: broadCastIdentifier2, broadcastCenter: broadcastCenter)
        AssertThatReceiverCountIs(1, identifier:broadCastIdentifier2)
        
        let receiverA2 = NotificationReceiver(identifier: broadCastIdentifier, broadcastCenter: broadcastCenter)
        AssertThatReceiverCountIs(2, identifier:broadCastIdentifier)
        
        let receiverB2 = NotificationReceiver(identifier: broadCastIdentifier2, broadcastCenter: broadcastCenter)
        AssertThatReceiverCountIs(2, identifier:broadCastIdentifier2)

        
        receiverA1.unSubscribe()
        AssertThatReceiverCountIs(1, identifier:broadCastIdentifier)
        AssertThatReceiverCountIs(2, identifier:broadCastIdentifier2)
        
        receiverB1.unSubscribe()
        AssertThatReceiverCountIs(1, identifier:broadCastIdentifier)
        AssertThatReceiverCountIs(1, identifier:broadCastIdentifier2)
        
        receiverB2.unSubscribe()
        AssertThatReceiverCountIs(1, identifier:broadCastIdentifier)
        AssertThatReceiverCountIs(0, identifier:broadCastIdentifier2)
        
        receiverB1.subscribe()
        receiverB2.subscribe()
        receiverA1.subscribe()
        AssertThatReceiverCountIs(2, identifier:broadCastIdentifier)
        AssertThatReceiverCountIs(2, identifier:broadCastIdentifier2)
        
        unSubscribeReceivers(receiverA1, receiverB1, receiverA2, receiverB2)
        AssertThatReceiverCountIs(0, identifier:broadCastIdentifier)
        AssertThatReceiverCountIs(0, identifier:broadCastIdentifier2)
    }
    
    
    func testBasicNotificationWithMultipleReceiver() {
        
        broadcastCenter.subscribe(self, selector: "getBroadcast:", identifier: broadCastIdentifier)
        
        let notification = BroadcastNotification(sender:self, identifier:broadCastIdentifier)
        broadcastCenter.post(notification)
        
        
        broadcastCenter.unSubscribe(self, identifier: broadCastIdentifier)
    }

    dynamic func getBroadcast(object:BroadcastNotification)
    {
        print("Hello :)")
    }
    
    
    private func AssertThatReceiverCountIs(count:Int, identifier:String = "id")
    {
        if let receivers = broadcastCenter.receiversForIdentifier(identifier)
        {
            let receiversCount = receivers.count
            XCTAssertEqual(receiversCount, count, "broadcast is ")
        }
        else if(count > 0)
        {
            XCTAssertTrue(false, "Cannot assert receiver count: Receriver list is nil")
        }
        
        
    }
    
    private func AssertThatReceiverIsInList(receiver:NotificationReceiver, identifier:String = "id")
    {
        let receivers = broadcastCenter.receiversForIdentifier(broadCastIdentifier)
        
        for listReceiver in receivers!
        {
            if listReceiver.1 as! NSObject == receiver
            {
                return
            }
        }
        
        XCTAssertTrue(false, "The receiver is not in the list")
    }
    
    private func AssertThatReceiverIsNotInList(receiver:NotificationReceiver)
    {
        let receivers = broadcastCenter.receiversForIdentifier(broadCastIdentifier)
        
        for listReceiver in receivers!
        {
            if listReceiver.1 as! NSObject == receiver
            {
                XCTAssertTrue(false, "The receiver is in the list")
                return
            }
        }
    }
    
    private func unSubscribeReceivers(receivers:NotificationReceiver...)
    {
        for receiver in receivers
        {
            receiver.unSubscribe()
        }
    }
    
    
    private class NotificationReceiver:NSObject
    {
        let broadcastCenter:BroadcastCenter
        let identifier:String
        var isBroadcastBeenCalled:Bool = false
        var broadcastCallsCount:Int = 0
        let selector:Selector = "getBroadcast:"
        
        init(identifier:String, broadcastCenter:BroadcastCenter)
        {
            self.broadcastCenter = broadcastCenter
            self.identifier = identifier
            super.init()
            
            subscribe()
        }
        
        func subscribe()
        {
            broadcastCenter.subscribe(self, selector: selector, identifier: identifier)
        }
        
        func unSubscribe()
        {
            broadcastCenter.unSubscribe(self, identifier: identifier)
        }
        
        
        deinit {
            unSubscribe()
        }
        
        dynamic func getBroadcast(object:BroadcastNotification)
        {
            broadcastCallsCount++
            isBroadcastBeenCalled = true
        }
    }
    
    

}
